Skip to content
This repository has been archived by the owner on Feb 8, 2018. It is now read-only.

Persist email verifications #4573

Closed
wants to merge 3 commits into from
Closed

Conversation

chadwhitacre
Copy link
Contributor

@chadwhitacre chadwhitacre commented Aug 16, 2017

Persist email messages (#4572) — Limit pending email verifications (#4571) →


Todo

  • Modify schema.
  • Change DELETE into INSERT.
  • Change SELECT to pull latest only.

@chadwhitacre chadwhitacre changed the base branch from master to save-emails August 16, 2017 09:26
@chadwhitacre
Copy link
Contributor Author

chadwhitacre commented Aug 16, 2017

Alright, the goal on this PR is to keep the Python API exactly the same, but have a record of email verifications in the database that is persistent across a) email removal/re-add, and b) account close/re-open. Here is the relevant API I find:

class Emails(object):               # gratipay.models.package.emails
    def classify_emails_for_participant(self, participant): pass

class Participant(object):          # gratipay.models.participant
    def clear_personal_information(self, cursor): pass

class Email(object):                # gratipay.models.participant.email
    def start_email_verification(self, email, *packages): pass
    def validate_email_verification_request(self, c, email, *packages): pass
    def get_email_verification_link(self, c, email, *packages): pass
    def get_email_verification_nonce(self, c, email): pass
    def set_primary_email(self, email, cursor=None): pass
    def _set_primary_email(self, email, cursor): pass
    def finish_email_verification(self, email, nonce): pass
    def save_email_address(self, cursor, address): pass
    def get_email(self, address, cursor=None, and_lock=False): pass
    def get_emails(self, cursor=None): pass
    def get_verified_email_addresses(self, cursor=None): pass
    def remove_email(self, address): pass
    def set_email_lang(self, accept_lang): pass

class Packages(object):             # gratipay.models.participant.packages
    def get_packages_for_claiming(self, manager): pass
    def start_package_claims(self, c, nonce, *packages): pass
    def get_packages_claiming(self, cursor, nonce): pass
    def finish_package_claims(self, cursor, nonce, *packages): pass

@chadwhitacre
Copy link
Contributor Author

Here are the places we delete from email_addresses (where verifications are stored as of #4572):

clear_personal_information

DELETE FROM email_addresses WHERE participant_id = %(participant_id)s;

take_over

DELETE FROM email_addresses
WHERE participant_id IN (%(dead)s, %(live)s)
AND id NOT IN (SELECT id FROM email_addresses_to_keep);

remove_email

c.run("DELETE FROM email_addresses WHERE participant_id=%s AND address=%s",
(self.id, address))

save_email_address

DELETE
FROM email_addresses
WHERE participant_id != %s
AND address=%s

@chadwhitacre
Copy link
Contributor Author

So basically we need to remove those DELETEs and then fix up the reads to only pull the "correct" verification.

@chadwhitacre
Copy link
Contributor Author

Here are the readers:

class Emails(object):               # gratipay.models.package.emails
    def classify_emails_for_participant(self, participant): pass

class Email(object):                # gratipay.models.participant.email
    def validate_email_verification_request(self, c, email, *packages): pass
    def get_email_verification_nonce(self, c, email): pass
    def save_email_address(self, cursor, address): pass
    def get_email(self, address, cursor=None, and_lock=False): pass
    def get_emails(self, cursor=None): pass

class Packages(object):             # gratipay.models.participant.packages
    def get_packages_for_claiming(self, manager): pass

@chadwhitacre
Copy link
Contributor Author

This is reminiscent of the schema design we use on payment_instructions, but there we can signal "no payment instruction" with a zero amount. What's the parallel here?

@chadwhitacre
Copy link
Contributor Author

Maybe a null verification_start?

CREATE TABLE email_addresses
( id                    serial                      PRIMARY KEY
, address               text                        NOT NULL
, verified              boolean                     DEFAULT NULL
                                                      CONSTRAINT verified_cant_be_false                                                                          -- Only use TRUE and NULL, so that the
                                                        -- unique constraint below functions
                                                        -- properly.
                                                        CHECK (verified IS NOT FALSE)
, nonce                 text
, verification_start    timestamp with time zone    NOT NULL
                                                      DEFAULT CURRENT_TIMESTAMP
, verification_end      timestamp with time zone
, participant_id        bigint                      NOT NULL
                                                      REFERENCES participants(id)
                                                      ON UPDATE RESTRICT
                                                      ON DELETE RESTRICT

, UNIQUE (address, verified) -- A verified email address can't be linked to multiple
                             -- participants. However, an *un*verified address *can*
                             -- be linked to multiple participants. We implement this
                             -- by using NULL instead of FALSE for the unverified
                             -- state, hence the check constraint on verified.
, UNIQUE (participant_id, address)
, CONSTRAINT emails_nonce_key UNIQUE (nonce)
 );

@chadwhitacre
Copy link
Contributor Author

I think we can get rid of verified and just use verification_end is not null. I also think we could rename verification_{start,end} to ts_{start,end} to match paydays.

@chadwhitacre
Copy link
Contributor Author

... but that also sounds like probable scope creep.

@chadwhitacre
Copy link
Contributor Author

Okay! Time to hack! 🕶️

@rohitpaulk rohitpaulk changed the base branch from save-emails to master August 19, 2017 13:10
@chadwhitacre
Copy link
Contributor Author

Over at #4571 (comment) I think I discovered that we should be able to do this with minimal schema changes. Closing in favor of #4579.

@chadwhitacre chadwhitacre deleted the persist-verifications branch August 23, 2017 11:20
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant